package com.code.commons.web.handler;

import com.code.commons.enums.ApiStyleEnum;
import com.code.commons.util.JsonUtil;
import com.code.commons.util.RequestContextUtil;
import com.code.commons.web.annotations.ResponseResult;
import com.code.commons.web.constants.HeaderConstants;
import com.code.commons.web.interceptor.ResponseResultInterceptor;
import com.code.commons.web.result.DefaultErrorResult;
import com.code.commons.web.result.PlatformResult;
import com.code.commons.web.result.Result;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * 接口响应体处理器
 * <p>
 * 备注：
 * 关于@ControllerAdvice注解、ResponseBodyAdvice接口是本功能的关键使用类，用于接口的响应体增强
 *
 * @author tangyifei
 * @since 2019-5-24 10:56:48
 */
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {

    /**
     * supports方法用于判断是否需要做增强转化
     * 备注：
     * supports方法中，加了个小功能，当调用人员不想要封装结果时，可以在header上设置参数Api-Style=none
     *
     * @param returnType    方法参数
     * @param converterType http信息转换器
     * @return 是否需要做增强转化结果
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        HttpServletRequest request = RequestContextUtil.getRequest();
        ResponseResult responseResultAnn = (ResponseResult) request.getAttribute(ResponseResultInterceptor.RESPONSE_RESULT);
        return null != responseResultAnn && !ApiStyleEnum.NONE.name().equalsIgnoreCase(request.getHeader(HeaderConstants.API_STYLE));
    }

    /**
     * beforeBodyWrite方法用于增加逻辑实现
     *
     * @param body                  响应体数据
     * @param returnType            方法参数
     * @param selectedContentType   MIME类型，比如application/json、application/x-www-form-urlencoded等
     * @param selectedConverterType http信息转换器类型
     * @param request               请求对象
     * @param response              响应对象
     * @return 统一响应的结果
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        ResponseResult responseResultAnn = (ResponseResult) RequestContextUtil.getRequest().getAttribute(ResponseResultInterceptor.RESPONSE_RESULT);

        Class<? extends Result> resultClazz = responseResultAnn.value();

        if (resultClazz.isAssignableFrom(PlatformResult.class)) {
            if (body instanceof DefaultErrorResult) {
                DefaultErrorResult defaultErrorResult = (DefaultErrorResult) body;
                return PlatformResult.builder()
                        .code(defaultErrorResult.getCode())
                        .msg(RequestContextUtil.getApplicationContext().getMessage(String.valueOf(defaultErrorResult.getCode()), null, LocaleContextHolder.getLocale()))
                        .data(defaultErrorResult.getErrors())
                        .build();
            } else if (body instanceof String) {
                return JsonUtil.object2Json(PlatformResult.success(body));
            }

            return PlatformResult.success(body);
        }

        return body;
    }

}
